/**
 * 手动实现系列
 * jsonp、
 * bind、apply、Object.create、throttle、debounce、sleep、
 * map、every、some、forEach、reduce、reduceRight
 */

/**
 * bind
 */
Function.prototype.bind = function (context) {
  let self = this;
  let args = Array.prototype.slice.call(arguments, 1);

  function F() {
  }

  F.prototype = this.prototype;
  let fbound = function () {
    self.apply(this instanceof context ? this : context,
        Array.prototype.concat.call(args, Array.prototype.slice.call(arguments)))
  };
  fbound.prototype = new F();
  return fbound;
};

/**
 * apply
 */
Function.prototype.apply = function (context, args) {
  context.fn = this;
  let result = context.fn(...args);
  delete context.fn;
  return result;
};

/**
 * Object.create()
 */
function create(paramProto) {
  if (typeof paramProto !== "object" || typeof paramProto !== "function") return;

  function F() {
  }

  F.prototype = paramProto;
  return new F();
}

/**
 * jsonp
 */
function jsonp({url, param, callback}) {
  return new Promise((resolve, reject) => {
    let script = document.createElement('script');
    window.callback = function (data) {
      resolve(data);
      document.body.removeChild('script');
    };
    let param = {...param, callback};
    let arr = [];
    for (let key in param) {
      arr.push(`${key}=${param[key]}`)
    }
    script.src = `${url}?${arr.join('&')}`;
    document.body.appendChild(script);
  })
}

/**
 * 节流：n秒内执行1次，时间没到频繁触发则直接return
 */
function throttle(fn, delay) {
  let canRun = true;
  return function () {
    if (!canRun) return;
    canRun = false;
    setTimeout(() => {
      fn.apply(this, arguments);
    }, delay)
  }
}

/**
 * 防抖：n秒后执行fn，时间没到频繁触发则重新计算时间n
 */
function debounce(fn, delay) {
  let timer = null;
  return function () {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, arguments)
    }, delay)
  }
}

/**
 * sleep
 */
function sleep(delay) {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      try {
        resolve();
      } catch (e) {
        reject(e)
      }
    }, delay)
  })
}

/**
 * map
 */
Array.prototype.map = function (cb) {
  let list = [];
  for (let i = 0; i < this.length; i++) {
    list.push(cb.call(this, this[i], i, this))
  }
  return list;
};

/**
 * forEach
 */
Array.prototype.forEach = function (cb) {
  for (let i = 0; i < this.length; i++) {
    cb.call(this, this[i], i, this);
  }
};

/**
 * every
 */
Array.prototype.every = function (cb) {
  for (let i = 0; i < this.length; i++) {
    if (!cb.call(this, this[i], i, this)) {
      return false;
    }
  }
  return true;
};

/**
 * some
 */
Array.prototype.some = function (cb) {
  for (let i = 0; i < this.length; i++) {
    if (cb.call(this, this[i], i, this)) {
      return true;
    }
  }
  return false;
};

/**
 * reduce
 */
Array.prototype.reduce = function (cb, initValue) {
  let preValue = initValue || this[0];
  for (let i = initValue ? 0 : 1; i < this.length; i++) {
    preValue = cb.call(preValue, this[i], i, this)
  }
  return preValue;
};

/**
 * reduceRight
 */
Array.prototype.reduceRight = function (cb, initValue) {
  let lastIndex = this.length - 1;
  let preValue = initValue || this[lastIndex];
  for (let i = initValue ? 0 : 1; i < this.length; i++) {
    preValue = cb.call(preValue, this[lastIndex - i], i, this)
  }
  return preValue;
};

/**
 * instanceof
 */
function instanceOf(son, father) {
  let fatherProto = father.prototype;
  while (son.__proto__) {
    if (son.__proto__ === fatherProto) return true;
    son = son.__proto__;
  }
  return false;
}

/**
 * new 发生了什么
 */
function Person(name) {
  this.name = name;

  // var obj = new Object();
  // obj.__proto__ = Person.prototype;
  // var result = Person.call(obj);
  // return result instanceof Object ? result : obj;
}

var p = new Person("小明");